/**
 * https://www.bilibili.com/video/BV1Mb411e7re?p=35
 * AD/DA介绍
 * AD（Analog to Digital）：模拟-数字转换，将模拟信号转换为计算机可操作的数字信号
 * DA（Digital to Analog）：数字-模拟转换，将计算机输出的数字信号转换为模拟信号
 * AD/DA转换打开了计算机与模拟信号的大门，极大的提高了计算机系统的应用范围，也为模拟信号数字化处理提供了可能
 * 
 * 硬件电路模型
 * AD转换通常有多个输入通道，用多路选择开关连接至AD转换器，以实现AD多路复用的目的，提高硬件利用率
 * AD/DA与单片机数据传送可使用并口（速度快、原理简单），也可使用串口（接线少、使用方便）
 * 可将AD/DA模块直接集成在单片机内，这样直接写入/读出寄存器就可进行AD/DA转换，单片机的IO口可直接复用为AD/DA的通道
 * 
 * https://www.bilibili.com/video/BV1Mb411e7re?p=36
 * AD/DA性能指标:
 * 分辨率：指AD/DA数字量的精细程度，通常用位数表示。例如，对于5V电源系统来说，8位的AD可将5V等分为256份，即数字量变化最小一个单位时，模拟量变化5V/256=0.01953125V，所以，8位AD的电压分辨率为0.01953125V，AD/DA的位数越高，分辨率就越高
 * 转换速度：表示AD/DA的最大采样/建立频率，通常用转换频率或者转换时间来表示，对于采样/输出高速信号，应注意AD/DA的转换速度
 */
#include <REGX52.H>
#include "Link/LCD1602_Utils.h"
#include "Link/Timer0_Utils.h"
#include "Link/AD_XPT2046_Utils.h"
#include "Link/ADC0804_Utils.h"
#include "Link/DAC0832_Utils.h"

static void AD_test();
static void DA_test();
static void Timer0_onTick();

static bit isTx1C = 1;

void main_AD_and_DA() {
    //要先打开CSAD(P0 口 U2 锁存器)
    ADC0804_Init(isTx1C);
    //LCD1602初始化(会关闭U1 & U2)
    LCD1602_Init(isTx1C);
    AD_test();
    DA_test();
    
    Timer0_Init(1000, 0);
    Timer0_setOnTickListener_Exact(1, &Timer0_onTick);

    while (1);
}

/**
 * TX-1C (要插上左侧 ADIN 跳线帽)
 */
static void AD_test() {
    if (isTx1C) {
        // ADC0804_Init(isTx1C);
        LCD1602_ShowString(1, 1, "ADC0804: ADJ");
    } else {
        //AD_XPT2046            电位器, 热敏电阻, 光敏电阻
        LCD1602_ShowString(1, 1, "ADJ  NTC  RG");
    }
}

static void DA_test() {
    if (isTx1C) {
        /**
         * DAC0832 操作, TX-1C 的数码管也是P0口, ∴关闭数码管
         */
        P2_6 = 0;
        P2_7 = 0;
        DAC0832_Init();
    } else {
        //视频使用的是 PWM, 见"16.DA_2.c"
    }
}

static void Timer0_onTick() {
    static unsigned char T0Count = 0, T0Count1 = 0, ADValue_TX, Light = 0xAA;
    static unsigned int ADValue_Video;
    T0Count ++;
    if (T0Count >= 255) {   //每255ms进入一次
        T0Count=0;
        if (isTx1C) {
            ADC0804_Start();
            ADValue_TX = ADC0804_ReadAD();
            //读取完了之后, P1数据口会被全置1. 所以重新让灯点亮(查看效果)
            P1 = ADValue_TX;
            LCD1602_ShowNum(2, 1, ADValue_TX, 3);
        } else {
            //(视频) 从AD_XPT2046读取 电位器
            ADValue_Video = XPT2046_ReadAD(AD_XPT2046_XP, 1, 1, 0, 0);
            LCD1602_ShowNum(2, 1, ADValue_Video, 3);
            //从AD_XPT2046读取 热敏电阻
            ADValue_Video = XPT2046_ReadAD(AD_XPT2046_YP, 1, 1, 0, 0);
            LCD1602_ShowNum(2, 5, ADValue_Video, 3);
            //从AD_XPT2046读取 光敏电阻
            ADValue_Video = XPT2046_ReadAD(AD_XPT2046_VBAT, 1, 1, 0, 0);
            LCD1602_ShowNum(2, 9, ADValue_Video, 3);
        }
    }
    //DAC0832, 10ms进入1次, 呼吸灯
    T0Count1++;
    if (T0Count1 > 9) {
        T0Count1 = 0;
        if (isTx1C) {
            DAC0832_Write(Light++);
        }
    }
}
